@use '@angular/cdk';
@use '@material/chips/chip' as mdc-chip;
@use '@material/chips/chip-theme' as mdc-chip-theme;
@use '../core/mdc-helpers/mdc-helpers';
@use '../core/style/layout-common';
@use '../core/focus-indicators/private' as focus-indicators-private;
@use '../core/tokens/m2/mdc/chip' as tokens-mdc-chip;
@use '../core/tokens/m2/mat/chip' as tokens-mat-chip;
@use '../core/tokens/token-utils';
@use '@material/theme/custom-properties' as mdc-custom-properties;

// The slots for tokens that will be configured in the theme can be emitted with no fallback.
@include mdc-custom-properties.configure($emit-fallback-values: false, $emit-fallback-vars: false) {
  $mdc-chip-token-slots: tokens-mdc-chip.get-token-slots();
  $mat-chip-token-slots: tokens-mat-chip.get-token-slots();

  // Add the MDC chip static styles.
  @include mdc-chip.static-styles();

  .mat-mdc-standard-chip {
    // Add the official slots for the MDC chip.
    @include mdc-chip-theme.theme-styles($mdc-chip-token-slots);
  }

  // The highlighted attribute is used to make the chip appear as selected on-demand,
  // aside from showing the selected indicator. We achieve this by re-mapping the base
  // tokens to the highlighted ones. Note that we only need to do this for the tokens
  // that we don't re-implement ourselves below.
  // TODO(crisbeto): with some future refactors we may be able to clean this up.
  .mat-mdc-chip-highlighted {
    @include token-utils.use-tokens(tokens-mdc-chip.$prefix, $mdc-chip-token-slots) {
      $highlighted-remapped-tokens: (
        with-icon-icon-color: with-icon-selected-icon-color,
        elevated-container-color: elevated-selected-container-color,
        label-text-color: selected-label-text-color,
        outline-width: flat-selected-outline-width,
      );

      @each $selected, $base in $highlighted-remapped-tokens {
        #{token-utils.get-token-variable($selected)}: var(token-utils.get-token-variable($base));
      }
    }
  }

  // Add additional slots for the MDC chip tokens, needed in Angular Material.
  $disabled-trailing-icon-opacity: 1;

  @include token-utils.use-tokens(tokens-mdc-chip.$prefix, $mdc-chip-token-slots) {
    .mat-mdc-chip-focus-overlay {
      @include token-utils.create-token-slot(background, focus-state-layer-color);

      .mat-mdc-chip-selected &,
      .mat-mdc-chip-highlighted & {
        @include token-utils.create-token-slot(background, selected-focus-state-layer-color);
      }

      .mat-mdc-chip:hover & {
        @include token-utils.create-token-slot(background, hover-state-layer-color);
        @include token-utils.create-token-slot(opacity, hover-state-layer-opacity);
      }

      .mat-mdc-chip-selected:hover,
      .mat-mdc-chip-highlighted:hover & {
        @include token-utils.create-token-slot(background, selected-hover-state-layer-color);
        @include token-utils.create-token-slot(opacity, selected-hover-state-layer-opacity);
      }

      .mat-mdc-chip.cdk-focused & {
        @include token-utils.create-token-slot(background, focus-state-layer-color);
        @include token-utils.create-token-slot(opacity, focus-state-layer-opacity);
      }

      .mat-mdc-chip-selected.cdk-focused &,
      .mat-mdc-chip-highlighted.cdk-focused & {
        @include token-utils.create-token-slot(background, selected-focus-state-layer-color);
        @include token-utils.create-token-slot(opacity, selected-focus-state-layer-opacity);
      }
    }

    .mdc-evolution-chip--disabled:not(.mdc-evolution-chip--selected) .mat-mdc-chip-avatar {
      @include token-utils.create-token-slot(opacity, with-avatar-disabled-avatar-opacity);
    }

    .mdc-evolution-chip--disabled .mdc-evolution-chip__icon--trailing {
      $disabled-trailing-icon-opacity:
        token-utils.get-token-variable(with-trailing-icon-disabled-trailing-icon-opacity);

      @include token-utils.create-token-slot(
          opacity, with-trailing-icon-disabled-trailing-icon-opacity);
    }

    .mdc-evolution-chip--disabled.mdc-evolution-chip--selected .mdc-evolution-chip__checkmark {
      @include token-utils.create-token-slot(opacity, with-icon-disabled-icon-opacity);
    }
  }

  @include token-utils.use-tokens(tokens-mat-chip.$prefix, $mat-chip-token-slots) {
    // Historically, MDC did not support disabled chips, so we needed our own disabled styles.
    // Now that MDC supports disabled styles, we should switch to using theirs.
    .mat-mdc-standard-chip {
      &.mdc-evolution-chip--disabled {
        @include token-utils.create-token-slot(opacity, disabled-container-opacity);
      }

      &.mdc-evolution-chip--selected,
      &.mat-mdc-chip-highlighted {
        .mdc-evolution-chip__icon--trailing {
          @include token-utils.create-token-slot(color, selected-trailing-icon-color);
        }

        &.mdc-evolution-chip--disabled .mdc-evolution-chip__icon--trailing {
          @include token-utils.create-token-slot(color, selected-disabled-trailing-icon-color);
        }
      }
    }

    .mat-mdc-chip-remove {
      @include token-utils.create-token-slot(opacity, trailing-action-opacity);

      &:focus {
        @include token-utils.create-token-slot(opacity, trailing-action-focus-opacity);
      }

      &::after {
        @include token-utils.create-token-slot(background, trailing-action-state-layer-color);
      }

      &:hover::after {
        @include token-utils.create-token-slot(opacity, trailing-action-hover-state-layer-opacity);
      }

      &:focus::after {
        @include token-utils.create-token-slot(opacity, trailing-action-focus-state-layer-opacity);
      }
    }

    .mat-mdc-chip-selected .mat-mdc-chip-remove::after,
    .mat-mdc-chip-highlighted .mat-mdc-chip-remove::after {
      @include token-utils.create-token-slot(
          background, selected-trailing-action-state-layer-color);
    }

    // If the trailing icon is a chip-remove button, we have to factor in the trailing action
    // opacity as well as the disabled opacity.
    .mdc-evolution-chip--disabled .mdc-evolution-chip__icon--trailing {
      &.mat-mdc-chip-remove {
        opacity: calc(
          var(#{token-utils.get-token-variable(trailing-action-opacity)}) *
          var(#{$disabled-trailing-icon-opacity})
        );

        &:focus {
          opacity: calc(
            var(#{token-utils.get-token-variable(trailing-action-focus-opacity)}) *
            var(#{$disabled-trailing-icon-opacity})
          );
        }
      }
    }
  }
}

// We *should* be able to include these styles through MDC's
// `theme-styles` mixin, but we can't at the time of writing.
@mixin _missing-mdc-theme-styles() {
  .mat-mdc-standard-chip {
    @include mdc-chip-theme.outline-style(solid);
    @include mdc-chip-theme.checkmark-size(mdc-chip-theme.$checkmark-size);
    @include mdc-chip-theme.trailing-action-size(mdc-chip-theme.$trailing-action-size);
    @include mdc-chip-theme.horizontal-padding(
      mdc-chip-theme.$leading-padding,
      mdc-chip-theme.$trailing-padding
    );
    @include mdc-chip-theme.with-graphic-horizontal-padding(
      mdc-chip-theme.$graphic-leading-padding,
      mdc-chip-theme.$graphic-trailing-padding,
      mdc-chip-theme.$trailing-padding
    );
    @include mdc-chip-theme.with-trailing-action-horizontal-padding(
      mdc-chip-theme.$leading-padding,
      mdc-chip-theme.$trailing-action-leading-padding,
      mdc-chip-theme.$trailing-action-trailing-padding
    );
    @include mdc-chip-theme.with-graphic-and-trailing-action-horizontal-padding(
      mdc-chip-theme.$graphic-leading-padding,
      mdc-chip-theme.$graphic-trailing-padding,
      mdc-chip-theme.$trailing-action-leading-padding,
      mdc-chip-theme.$trailing-action-trailing-padding
    );
  }

  .mdc-evolution-chip--with-avatar {
    @include mdc-chip-theme.with-graphic-horizontal-padding(
      mdc-chip-theme.$avatar-leading-padding,
      mdc-chip-theme.$avatar-trailing-padding,
      mdc-chip-theme.$trailing-padding
    );
    @include mdc-chip-theme.with-graphic-and-trailing-action-horizontal-padding(
      mdc-chip-theme.$avatar-leading-padding,
      mdc-chip-theme.$avatar-trailing-padding,
      mdc-chip-theme.$trailing-action-leading-padding,
      mdc-chip-theme.$trailing-action-trailing-padding
    );
  }
}

@include mdc-helpers.disable-mdc-fallback-declarations {
  @include _missing-mdc-theme-styles();
}

.mat-mdc-standard-chip {
  -webkit-tap-highlight-color: transparent;

  @include cdk.high-contrast(active, off) {
    outline: solid 1px;

    .mdc-evolution-chip__checkmark-path {
      // SVG colors won't be changed in high contrast mode and since the checkmark is white
      // by default, it'll blend in with the background in black-on-white mode. Override the
      // color to ensure that it's visible. We need !important, because the theme styles are
      // very specific.
      stroke: CanvasText !important;
    }
  }

  // MDC sets `overflow: hidden` on these elements in order to truncate the text. This is
  // unnecessary since our chips don't truncate their text and it makes it difficult to style
  // the strong focus indicators so we need to override it.
  .mdc-evolution-chip__cell--primary,
  .mdc-evolution-chip__action--primary,
  .mat-mdc-chip-action-label {
    overflow: visible;
  }

  // Ensures that the trailing icon is pushed to the end if the chip has a set width.
  .mdc-evolution-chip__cell--primary {
    flex-basis: 100%;
  }

  // This element can be placed on a `button` node which usually has some user agent styles.
  // Reset the font so that the typography from the root element can propagate down.
  .mdc-evolution-chip__action--primary {
    font: inherit;
    letter-spacing: inherit;
    white-space: inherit;
  }

  // MDC sizes and positions this element using `width`, `height` and `padding`.
  // This usually works, but it's common for apps to add `box-sizing: border-box`
  // to all elements on the page which can cause the graphic to be clipped.
  // Set an explicit `box-sizing` in order to avoid these issues.
  .mat-mdc-chip-graphic,
  .mat-mdc-chip-trailing-icon {
    box-sizing: content-box;
  }

  &._mat-animation-noopable {
    &,
    .mdc-evolution-chip__graphic,
    .mdc-evolution-chip__checkmark,
    .mdc-evolution-chip__checkmark-path {
      // MDC listens to `transitionend` events on some of these
      // elements so we can't disable the transitions completely.
      transition-duration: 1ms;
      animation-duration: 1ms;
    }
  }
}

// Keeps basic listbox chips looking consistent with the other variations. Listbox chips don't
// inherit the font size, because they wrap the label in a `button` that has user agent styles.
.mat-mdc-basic-chip .mdc-evolution-chip__action--primary {
  font: inherit;
}

// MDC's focus and hover indication is handled through their ripple which we currently
// don't use due to size concerns so we have to re-implement it ourselves.
.mat-mdc-chip-focus-overlay {
  @include layout-common.fill;
  pointer-events: none;
  opacity: 0;
  border-radius: inherit;
  transition: opacity 150ms linear;

  ._mat-animation-noopable & {
    transition: none;
  }

  .mat-mdc-basic-chip & {
    display: none;
  }
}

// The ripple container should match the bounds of the entire chip.
.mat-mdc-chip .mat-ripple.mat-mdc-chip-ripple {
  @include layout-common.fill;

  // Disable pointer events for the ripple container and state overlay because the container
  // will overlay the user content and we don't want to disable mouse events on the user content.
  // Pointer events can be safely disabled because the ripple trigger element is the host element.
  pointer-events: none;

  // Inherit the border radius from the parent so that state overlay and ripples don't exceed the
  // parent button boundaries.
  border-radius: inherit;
}

.mat-mdc-chip-avatar {
  // In case an icon or text is used as an avatar.
  text-align: center;
  line-height: 1;

  // Technically the avatar is only supposed to have an image, but we also allow for icons.
  // Set the color so the icons inherit the correct color.
  color: var(--mdc-chip-with-icon-icon-color, currentColor);
}

// Required for the strong focus indicator to fill the chip.
.mat-mdc-chip {
  position: relative;

  // `.mat-mdc-chip-action-label` below sets a `z-index: 1` to put the label above the focus
  // overlay, but that can also cause it to appear above other elements like sticky columns
  // (see #26793). Set an explicit `z-index` to prevent the label from leaking out.
  z-index: 0;
}

.mat-mdc-chip-action-label {
  // MDC centers the text, but we have a lot of internal customers who have it at the start.
  text-align: left;

  [dir='rtl'] & {
    text-align: right;
  }

  // When a chip has a trailing action, it'll have two focusable elements when navigating with
  // the arrow keys: the primary action and the trailing one. If that's the case, we apply
  // `position: relative` to the primary action container so that the indicators is only around
  // the text label. This allows for it to be distinguished from the indicator on the trailing icon.
  .mat-mdc-chip.mdc-evolution-chip--with-trailing-action & {
    position: relative;
  }

  .mat-mdc-chip-primary-focus-indicator {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    pointer-events: none;
  }

  // For the chip element, default inset/offset values are necessary to ensure that
  // the focus indicator is sufficiently contrastive and renders appropriately.
  .mat-mdc-focus-indicator::before {
    $default-border-width: focus-indicators-private.$default-border-width;
    $border-width: var(--mat-mdc-focus-indicator-border-width, #{$default-border-width});
    $offset: calc(#{$border-width} + 2px);
    margin: calc(#{$offset} * -1);
  }

  // Give the text label a higher z-index than the focus overlay to ensure that the focus overlay
  // does not affect the color of the text. Material spec requires state layer to not interfere with
  // text color.
  z-index: 1;
}

.mat-mdc-chip-remove {
  &::before {
    $default-border-width: focus-indicators-private.$default-border-width;
    $offset: var(--mat-mdc-focus-indicator-border-width, #{$default-border-width});
    margin: calc(#{$offset} * -1);

    // MDC sets a padding a on the chip button which stretches out the focus indicator.
    left: 8px;
    right: 8px;
  }

  // Used as a state overlay.
  &::after {
    $offset: 2px;
    content: '';
    display: block;
    opacity: 0;
    position: absolute;
    top: 0 - $offset;
    bottom: 0 - $offset;
    left: 8px - $offset;
    right: 8px - $offset;
    border-radius: 50%;
  }

  .mat-icon {
    width: mdc-chip-theme.$trailing-action-size;
    height: mdc-chip-theme.$trailing-action-size;
    font-size: mdc-chip-theme.$trailing-action-size;
    box-sizing: content-box;
  }
}

.mat-chip-edit-input {
  cursor: text;
  display: inline-block;
  color: inherit;
  outline: 0;
}

// Single-selection chips show their selected state using a background color which won't be visible
// in high contrast mode. This isn't necessary in multi-selection since there's a checkmark.
.mat-mdc-chip-selected:not(.mat-mdc-chip-multiple) {
  @include cdk.high-contrast(active, off) {
    outline-width: 3px;
  }
}

// The chip has multiple focus targets so we have to put the indicator on
// a separate element, rather than on the focusable element itself.
.mat-mdc-chip-action:focus .mat-mdc-focus-indicator::before {
  content: '';
}
